دليل شامل لـ Solid Router، الموجّه الرسمي من جانب العميل لـ SolidJS، يغطي التثبيت والاستخدام والميزات المتقدمة وأفضل الممارسات لبناء تطبيقات ويب سلسة أحادية الصفحة.
Solid Router: إتقان التنقل من جانب العميل في SolidJS
يوفر SolidJS، المعروف بأدائه الاستثنائي وبساطته، أساسًا رائعًا لبناء تطبيقات الويب الحديثة. لإنشاء تجارب تفاعلية وسهلة الاستخدام حقًا، يعد وجود موجّه قوي من جانب العميل أمرًا ضروريًا. وهنا يأتي دور Solid Router، الموجّه الرسمي والموصى به لـ SolidJS، والمصمم للتكامل بسلاسة مع مبادئ إطار العمل التفاعلية.
سيتعمق هذا الدليل الشامل في عالم Solid Router، حيث يغطي كل شيء بدءًا من الإعداد الأساسي إلى التقنيات المتقدمة لبناء تطبيقات معقدة وديناميكية أحادية الصفحة (SPAs). سواء كنت مطور SolidJS متمرسًا أو مبتدئًا، فإن هذا المقال سيزودك بالمعرفة والمهارات اللازمة لإتقان التنقل من جانب العميل.
ما هو Solid Router؟
Solid Router هو موجّه خفيف الوزن وعالي الأداء من جانب العميل مصمم خصيصًا لـ SolidJS. يستفيد من تفاعلية SolidJS لتحديث واجهة المستخدم بكفاءة بناءً على التغييرات في عنوان URL للمتصفح. على عكس الموجهات التقليدية التي تعتمد على مقارنة DOM الافتراضي (virtual DOM diffing)، يقوم Solid Router بمعالجة DOM مباشرة، مما يؤدي إلى أداء أسرع وأكثر قابلية للتنبؤ.
تشمل الميزات الرئيسية لـ Solid Router ما يلي:
- التوجيه التصريحي: حدد مساراتك باستخدام واجهة برمجة تطبيقات (API) بسيطة وبديهية تعتمد على JSX.
- التوجيه الديناميكي: تعامل بسهولة مع المسارات ذات المعلمات، مما يتيح لك إنشاء تطبيقات ديناميكية قائمة على البيانات.
- المسارات المتداخلة: نظم تطبيقك في أقسام منطقية باستخدام المسارات المتداخلة.
- مكون الرابط (Link Component): تنقل بسلاسة بين المسارات باستخدام مكون
<A>، الذي يتعامل تلقائيًا مع تحديثات عنوان URL وتنسيق الروابط النشطة. - تحميل البيانات: قم بتحميل البيانات بشكل غير متزامن قبل عرض المسار، مما يضمن تجربة مستخدم سلسة.
- الانتقالات: أنشئ انتقالات جذابة بصريًا بين المسارات لتحسين تجربة المستخدم.
- معالجة الأخطاء: تعامل مع الأخطاء بأناقة واعرض صفحات خطأ مخصصة.
- التكامل مع History API: يتكامل بسلاسة مع واجهة برمجة تطبيقات السجل (History API) الخاصة بالمتصفح، مما يسمح للمستخدمين بالتنقل باستخدام أزرار الرجوع والتقدم.
البدء مع Solid Router
التثبيت
لتثبيت Solid Router، استخدم مدير الحزم المفضل لديك:
npm install @solidjs/router
yarn add @solidjs/router
pnpm add @solidjs/router
الإعداد الأساسي
يدور جوهر Solid Router حول مكوني <Router> و <Route>. يعمل مكون <Router> كجذر لنظام التوجيه في تطبيقك، بينما تحدد مكونات <Route> الربط بين عناوين URL والمكونات.
إليك مثال أساسي:
import { Router, Route } from '@solidjs/router';
import Home from './components/Home';
import About from './components/About';
function App() {
return (
<Router>
<Route path="/"> <Home/> </Route>
<Route path="/about"> <About/> </Route>
</Router>
);
}
export default App;
في هذا المثال، يغلف مكون <Router> التطبيق بأكمله. تحدد مكونات <Route> مسارين: أحدهما للمسار الجذر ("/") والآخر لمسار "/about". عندما يتنقل المستخدم إلى أي من هذين المسارين، سيتم عرض المكون المقابل (Home أو About).
مكون <A>
للتنقل بين المسارات، استخدم مكون <A> الذي يوفره Solid Router. هذا المكون مشابه لوسم HTML العادي <a>، ولكنه يتعامل تلقائيًا مع تحديثات عنوان URL ويمنع إعادة تحميل الصفحة بالكامل.
import { A } from '@solidjs/router';
function Navigation() {
return (
<nav>
<A href="/">Home</A>
<A href="/about">About</A>
</nav>
);
}
export default Navigation;
عندما ينقر المستخدم على أحد هذه الروابط، سيقوم Solid Router بتحديث عنوان URL للمتصفح وعرض المكون المقابل دون التسبب في إعادة تحميل الصفحة بالكامل.
تقنيات التوجيه المتقدمة
التوجيه الديناميكي مع معلمات المسار
يدعم Solid Router التوجيه الديناميكي، مما يتيح لك إنشاء مسارات ذات معلمات. هذا مفيد لعرض المحتوى بناءً على معرف (ID) أو اسم فريد (slug) معين.
import { Router, Route } from '@solidjs/router';
import UserProfile from './components/UserProfile';
function App() {
return (
<Router>
<Route path="/users/:id"> <UserProfile/> </Route>
</Router>
);
}
export default App;
في هذا المثال، المقطع :id في المسار هو معلمة مسار. للوصول إلى قيمة المعلمة id داخل مكون UserProfile، يمكنك استخدام الخطاف useParams:
import { useParams } from '@solidjs/router';
import { createResource } from 'solid-js';
function UserProfile() {
const params = useParams();
const [user] = createResource(() => params.id, fetchUser);
return (
<div>
<h1>User Profile</h1>
{user() ? (
<div>
<p>Name: {user().name}</p>
<p>Email: {user().email}</p>
</div>
) : (<p>Loading...</p>)}
</div>
);
}
async function fetchUser(id: string) {
const response = await fetch(`https://api.example.com/users/${id}`);
return response.json();
}
export default UserProfile;
يعيد الخطاف useParams كائنًا يحتوي على معلمات المسار. في هذه الحالة، سيحتوي params.id على قيمة المعلمة id من عنوان URL. يتم بعد ذلك استخدام الخطاف createResource لجلب بيانات المستخدم بناءً على المعرف.
مثال دولي: تخيل منصة تجارة إلكترونية عالمية. يمكنك استخدام التوجيه الديناميكي لعرض تفاصيل المنتج بناءً على معرف المنتج: /products/:productId. يتيح لك ذلك إنشاء عناوين URL فريدة لكل منتج بسهولة، مما يسهل على المستخدمين مشاركة العناصر المحددة ووضع إشارة مرجعية عليها، بغض النظر عن موقعهم.
المسارات المتداخلة
تسمح لك المسارات المتداخلة بتنظيم تطبيقك في أقسام منطقية. هذا مفيد بشكل خاص للتطبيقات المعقدة ذات مستويات التنقل المتعددة.
import { Router, Route } from '@solidjs/router';
import Dashboard from './components/Dashboard';
import Profile from './components/Profile';
import Settings from './components/Settings';
function App() {
return (
<Router>
<Route path="/dashboard">
<Dashboard/>
<Route path="/profile"> <Profile/> </Route>
<Route path="/settings"> <Settings/> </Route>
</Route>
</Router>
);
}
export default App;
في هذا المثال، يعمل مكون <Dashboard> كحاوية لمكوني <Profile> و <Settings>. يتم تداخل مساري <Profile> و <Settings> داخل مسار <Dashboard>، مما يعني أنهما لن يتم عرضهما إلا عندما يكون المستخدم على مسار "/dashboard".
لعرض المسارات المتداخلة داخل مكون <Dashboard>، تحتاج إلى استخدام مكون <Outlet>:
import { Outlet } from '@solidjs/router';
function Dashboard() {
return (
<div>
<h1>Dashboard</h1>
<nav>
<A href="/dashboard/profile">Profile</A>
<A href="/dashboard/settings">Settings</A>
</nav>
<Outlet/>
</div>
);
}
export default Dashboard;
يعمل مكون <Outlet> كعنصر نائب حيث سيتم عرض المسارات المتداخلة. عندما يتنقل المستخدم إلى "/dashboard/profile"، سيتم عرض مكون <Profile> داخل مكون <Outlet>. وبالمثل، عندما يتنقل المستخدم إلى "/dashboard/settings"، سيتم عرض مكون <Settings> داخل مكون <Outlet>.
تحميل البيانات باستخدام createResource
يعد تحميل البيانات بشكل غير متزامن قبل عرض المسار أمرًا بالغ الأهمية لتوفير تجربة مستخدم سلسة. يتكامل Solid Router بسلاسة مع خطاف createResource الخاص بـ SolidJS، مما يجعل تحميل البيانات أمرًا سهلاً.
لقد رأينا مثالاً على ذلك في مكون UserProfile سابقًا، ولكن ها هو مرة أخرى للتوضيح:
import { useParams } from '@solidjs/router';
import { createResource } from 'solid-js';
function UserProfile() {
const params = useParams();
const [user] = createResource(() => params.id, fetchUser);
return (
<div>
<h1>User Profile</h1>
{user() ? (
<div>
<p>Name: {user().name}</p>
<p>Email: {user().email}</p>
</div>
) : (<p>Loading...</p>)}
</div>
);
}
async function fetchUser(id: string) {
const response = await fetch(`https://api.example.com/users/${id}`);
return response.json();
}
export default UserProfile;
يأخذ الخطاف createResource وسيطتين: إشارة (signal) تؤدي إلى تحميل البيانات، ودالة تقوم بجلب البيانات. في هذه الحالة، الإشارة هي () => params.id، مما يعني أنه سيتم جلب البيانات كلما تغيرت المعلمة id. تقوم الدالة fetchUser بجلب بيانات المستخدم من واجهة برمجة تطبيقات (API) بناءً على المعرف.
يعيد الخطاف createResource مصفوفة تحتوي على المورد (البيانات التي تم جلبها) ودالة لإعادة جلب البيانات. المورد هو إشارة (signal) تحتفظ بالبيانات. يمكنك الوصول إلى البيانات عن طريق استدعاء الإشارة (user()). إذا كانت البيانات لا تزال قيد التحميل، فستعيد الإشارة undefined. يتيح لك هذا عرض مؤشر تحميل أثناء جلب البيانات.
الانتقالات
يمكن أن تؤدي إضافة انتقالات بين المسارات إلى تحسين تجربة المستخدم بشكل كبير. على الرغم من أن Solid Router لا يحتوي على دعم مدمج للانتقالات، إلا أنه يتكامل جيدًا مع مكتبات مثل solid-transition-group لتحقيق انتقالات سلسة وجذابة بصريًا.
أولاً، قم بتثبيت حزمة solid-transition-group:
npm install solid-transition-group
yarn add solid-transition-group
pnpm add solid-transition-group
بعد ذلك، قم بتغليف مساراتك بمكون <TransitionGroup>:
import { Router, Route } from '@solidjs/router';
import { TransitionGroup, Transition } from 'solid-transition-group';
import Home from './components/Home';
import About from './components/About';
function App() {
return (
<Router>
<TransitionGroup>
<Route path="/">
<Transition name="fade" duration={300}>
<Home/>
</Transition>
</Route>
<Route path="/about">
<Transition name="fade" duration={300}>
<About/>
</Transition>
</Route>
</TransitionGroup>
</Router>
);
}
export default App;
في هذا المثال، يتم تغليف كل مسار بمكون <Transition>. تحدد الخاصية name بادئة فئة CSS للانتقال، وتحدد الخاصية duration مدة الانتقال بالمللي ثانية.
ستحتاج إلى تحديد فئات CSS المقابلة للانتقال في ملف الأنماط الخاص بك:
.fade-enter {
opacity: 0;
}
.fade-enter-active {
opacity: 1;
transition: opacity 300ms ease-in;
}
.fade-exit {
opacity: 1;
}
.fade-exit-active {
opacity: 0;
transition: opacity 300ms ease-out;
}
يحدد كود CSS هذا انتقالًا بسيطًا من نوع التلاشي للداخل والخارج (fade-in/fade-out). عند الدخول إلى مسار، يتم تطبيق الفئتين .fade-enter و .fade-enter-active، مما يؤدي إلى ظهور المكون تدريجيًا. عند الخروج من مسار، يتم تطبيق الفئتين .fade-exit و .fade-exit-active، مما يؤدي إلى اختفاء المكون تدريجيًا.
معالجة الأخطاء
تعد معالجة الأخطاء بأناقة أمرًا ضروريًا لتوفير تجربة مستخدم جيدة. لا يحتوي Solid Router على معالجة أخطاء مدمجة، ولكن يمكنك تنفيذها بسهولة باستخدام حدود خطأ عامة (global error boundary) أو معالج أخطاء خاص بالمسار.
إليك مثال على حدود الخطأ العامة:
import { createSignal, Suspense, ErrorBoundary } from 'solid-js';
import { Router, Route } from '@solidjs/router';
import Home from './components/Home';
import About from './components/About';
function App() {
const [error, setError] = createSignal(null);
return (
<ErrorBoundary fallback={<p>Something went wrong: {error()?.message}</p>}>
<Suspense fallback={<p>Loading...</p>}>
<Router>
<Route path="/"> <Home/> </Route>
<Route path="/about"> <About/> </Route>
</Router>
</Suspense>
</ErrorBoundary>
);
}
export default App;
يلتقط مكون <ErrorBoundary> أي أخطاء تحدث داخل عناصره الفرعية. تحدد الخاصية fallback المكون الذي سيتم عرضه عند حدوث خطأ. في هذه الحالة، يعرض فقرة تحتوي على رسالة الخطأ.
يتعامل مكون <Suspense> مع الوعود (promises) المعلقة، ويستخدم عادةً مع المكونات غير المتزامنة أو تحميل البيانات. يعرض الخاصية `fallback` حتى يتم حل الوعود.
لإحداث خطأ، يمكنك إطلاق استثناء داخل مكون:
function Home() {
throw new Error('Failed to load home page');
return <h1>Home</h1>;
}
export default Home;
عند تنفيذ هذا الكود، سيلتقط مكون <ErrorBoundary> الخطأ ويعرض المكون الاحتياطي (fallback component).
اعتبارات دولية: عند عرض رسائل الخطأ، ضع في اعتبارك التدويل (i18n). استخدم مكتبة ترجمة لتقديم رسائل الخطأ باللغة المفضلة للمستخدم. على سبيل المثال، إذا واجه مستخدم في اليابان خطأ، يجب أن يرى رسالة الخطأ باللغة اليابانية، وليس الإنجليزية.
أفضل الممارسات لاستخدام Solid Router
- حافظ على تنظيم مساراتك: استخدم المسارات المتداخلة لتنظيم تطبيقك في أقسام منطقية. سيجعل هذا من السهل صيانة الكود والتنقل فيه.
- استخدم معلمات المسار للمحتوى الديناميكي: استخدم معلمات المسار لإنشاء عناوين URL ديناميكية لعرض المحتوى بناءً على معرف (ID) أو اسم فريد (slug) معين.
- قم بتحميل البيانات بشكل غير متزامن: قم بتحميل البيانات بشكل غير متزامن قبل عرض المسار لتوفير تجربة مستخدم سلسة.
- أضف انتقالات بين المسارات: استخدم الانتقالات لتحسين تجربة المستخدم وجعل تطبيقك يبدو أكثر احترافية.
- تعامل مع الأخطاء بأناقة: قم بتنفيذ معالجة الأخطاء لالتقاط وعرض الأخطاء بطريقة سهلة الاستخدام.
- استخدم أسماء مسارات وصفية: اختر أسماء مسارات تعكس بدقة محتوى المسار. سيجعل هذا فهم بنية تطبيقك أسهل.
- اختبر مساراتك: اكتب اختبارات وحدة (unit tests) للتأكد من أن مساراتك تعمل بشكل صحيح. سيساعدك هذا على اكتشاف الأخطاء مبكرًا ومنع التراجعات (regressions).
الخاتمة
Solid Router هو موجّه قوي ومرن من جانب العميل يتكامل بسلاسة مع SolidJS. من خلال إتقان ميزاته واتباع أفضل الممارسات، يمكنك بناء تطبيقات معقدة وديناميكية أحادية الصفحة توفر تجربة مستخدم سلسة وجذابة. بدءًا من الإعداد الأساسي إلى التقنيات المتقدمة مثل التوجيه الديناميكي وتحميل البيانات والانتقالات، زودك هذا الدليل بالمعرفة والمهارات اللازمة للتنقل بثقة في عالم التنقل من جانب العميل في SolidJS. احتضن قوة Solid Router وأطلق العنان للإمكانات الكاملة لتطبيقات SolidJS الخاصة بك!
تذكر الرجوع إلى وثائق Solid Router الرسمية للحصول على أحدث المعلومات والأمثلة: [رابط وثائق Solid Router - عنصر نائب]
استمر في بناء أشياء مذهلة مع SolidJS!